﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using SoetemanSoftware.Umb.Datatypes.MacroPicker.Factory;
using SoetemanSoftware.Umb.Datatypes.MacroPicker.Types;
using umbraco;
using umbraco.cms.businesslogic.macro;
using umbraco.interfaces;
using umbraco.presentation.webservices;

namespace SoetemanSoftware.Umb.Datatypes.MacroPicker
{
    /// <summary>
    /// This is the class that holds functionality for Data Editor that the content manager uses in Umbraco
    /// </summary>
    public class MacroPickerDataEditor : UpdatePanel, IDataEditor
    {
        #region Private Fields
        private IData _data;
        private Hashtable _dataValues;
        private DropDownList _macroSelectDropdown;
        private List<string> _allowedMacros;
        private Table _formTable = new Table();
        #endregion

        #region Constructor
        public MacroPickerDataEditor(IData data, List<string> allowedMacros)
        {
            Data = data;
            AllowedMacros = allowedMacros;
        }
        #endregion

        #region Overrides
        /// <summary>
        /// Initializes controls and add them to the control tree
        /// </summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            //Make sure the modal is registred
            base.Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "subModal", "<script type=\"text/javascript\" src=\"" + GlobalSettings.Path + "/js/submodal/common.js\"></script><script type=\"text/javascript\" src=\"" + GlobalSettings.Path + "/js/submodal/subModal.js\"></script><link href=\"" + GlobalSettings.Path + "/js/submodal/subModal.css\" type=\"text/css\" rel=\"stylesheet\"></link>");
            // We need to make sure we have a reference to the legacy ajax calls in the scriptmanager
            ajaxHelpers.EnsureLegacyCalls(base.Page);

            //Init properties for the Macro select dropdownlist
            MacroSelectDropdown = new DropDownList();
            MacroSelectDropdown.ID = EnsureUniqueID("macroSelectDropdown");
            MacroSelectDropdown.SelectedIndexChanged += new EventHandler(macroSelectDropdown_SelectedIndexChanged);
            MacroSelectDropdown.AutoPostBack = true;

            //Add Macros to pulldown list
            PopulateMacroDropDown();

            //Init properties for the macro properties form Placeholder
            FormTable.ID = EnsureUniqueID("FormTable");

            //Add controls to the control collection
            this.ContentTemplateContainer.Controls.Add(MacroSelectDropdown);
            this.ContentTemplateContainer.Controls.Add(FormTable);
        }

        /// <summary>
        /// Initioalizes the form
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (!Page.IsPostBack)
            {
                //Handle Initial Request
                if (DataValues["macroalias"] != null)
                {
                    //Data is available from the database, initialize the form with the data
                    string alias = DataValues["macroalias"].ToString();

                    //Set Pulldown selected value based on the macro alias
                    MacroSelectDropdown.SelectedValue = alias;

                    //Create from with values based on the alias
                    InitializeForm(alias);
                }
            }
            else
            {
                //Render form if properties are in the viewstate
                if (SelectedProperties.Count > 0)
                {
                    RendeFormControls();
                }
            }
            //Make sure child controls get rendered
            EnsureChildControls();
        }
        #endregion

        #region Event Handlers
        private void macroSelectDropdown_SelectedIndexChanged(object sender, EventArgs e)
        {
            InitializeForm(MacroSelectDropdown.SelectedValue);
        }
        #endregion

        #region Methods

        /// <summary>
        /// If mulitple instances of the Control are placed on a form asp.net throws an error
        /// Because Id's are not Unique. This method Concats the control Id to the ID that we use
        /// So This is always unique
        /// </summary>
        /// <param name="id"></param>
        private string EnsureUniqueID(string controlID)
        {
            return string.Format("{0}_{1}", ID, controlID);
        }

        /// <summary>
        /// Adds all allowed Macro items to the Macro Pulldown menu
        /// </summary>
        private void PopulateMacroDropDown()
        {
            MacroSelectDropdown.Items.Add(new ListItem(umbraco.ui.Text("choose"), ""));
            foreach (string item in AllowedMacros)
            {
                MacroSelectDropdown.Items.Add(new ListItem(Macro.GetByAlias(item).Name, item));
            }
        }

        /// <summary>
        /// Get Propety Info and create a form based on the alias of the form
        /// </summary>
        /// <param name="macroAlias"></param>
        private void InitializeForm(string macroAlias)
        {

            //Hold selected Alias in Viewstate
            SelectedMacroAlias = macroAlias;

            //Create new property collection
            List<PersistableMacroProperties> props = new List<PersistableMacroProperties>();

            //Clear Old Control Collection
            FormTable.Controls.Clear();

            //Is a Macro selected
            if (!string.IsNullOrEmpty(macroAlias))
            {
                Macro formMacro = Macro.GetByAlias(macroAlias);

                ///Only render form when macro is found
                if (formMacro != null)
                {
                    foreach (MacroProperty macroProperty in formMacro.Properties)
                    {
                        //Only add properties that people may see.
                        if (macroProperty.Public)
                        {
                            PersistableMacroProperties prop = new PersistableMacroProperties();
                            prop.Alias = macroProperty.Alias;
                            prop.Name = macroProperty.Name;
                            prop.AssemblyName = macroProperty.Type.Assembly;
                            prop.TypeName = macroProperty.Type.Type;

                            //Assign value if specified
                            if (DataValues[macroProperty.Alias.ToLower()] != null)
                            {
                                prop.Value = DataValues[macroProperty.Alias.ToLower()].ToString();
                            }

                            props.Add(prop);
                        }
                    }
                }
            }
            //Hold selected properties in ViewState
            SelectedProperties = props;

            //Render the form
            RendeFormControls();
        }

        /// <summary>
        /// Renders a from based on the properties of the macro
        /// </summary>
        private void RendeFormControls()
        {
            foreach (PersistableMacroProperties prop in SelectedProperties)
            {
                //Create Literal
                Literal caption = new Literal();
                caption.ID = EnsureUniqueID(string.Format("{0}Label", prop.Alias));
                caption.Text = prop.Name;

                //Get the MacroControl 
                Control macroControl = MacroControlFactory.GetMacroRenderControlByType(prop, EnsureUniqueID(prop.Alias));

                AddFormRow(caption, macroControl);
                
            }
        }

        /// <summary>
        /// Add a new TableRow to the table. with two cells that holds the Caption and the  form element
        /// </summary>
        /// <param name="name"></param>
        /// <param name="formElement"></param>
        private void AddFormRow(Control name, Control formElement)
        {
            string aliasPrefix = formElement.ID;

            TableRow tr = new TableRow();
            tr.ID = EnsureUniqueID(string.Format("{0}tr", aliasPrefix));

            TableCell tcLeft = new TableCell();
            tcLeft.ID = EnsureUniqueID(string.Format("{0}tcleft", aliasPrefix));
            tcLeft.Width = 120;

            TableCell tcRight = new TableCell();
            tcRight.ID = EnsureUniqueID(string.Format("{0}tcright", aliasPrefix));
            tcRight.Width = 300;

            tcLeft.Controls.Add(name);
            tcRight.Controls.Add(formElement);

            tr.Controls.Add(tcLeft);
            tr.Controls.Add(tcRight);

            FormTable.Controls.Add(tr);
            
        }

        /// <summary>
        /// Builds an Umbraco Macro tag if a user selected a macro
        /// </summary>
        /// <returns></returns>
        private string CreateUmbracoMacroTag()
        {
            string result = string.Empty;

            if (!string.IsNullOrEmpty(SelectedMacroAlias))
            {
                //Only create Macro Tag if we have something to store.
                StringBuilder sb = new StringBuilder();
                //Start
                sb.Append("<?UMBRACO_MACRO ");

                //Alias Attribute
                sb.AppendFormat(" macroalias=\"{0}\" ", SelectedMacroAlias);

                foreach (PersistableMacroProperties prop in SelectedProperties)
                {
                    //Make sure we find the correct Unique ID
                    string ControlIdToFind = EnsureUniqueID(prop.Alias);
                    string value = MacroControlFactory.GetValueFromMacroControl(FormTable.FindControl(ControlIdToFind));
                    sb.AppendFormat(" {0}=\"{1}\" ", prop.Alias, value);
                }
                sb.Append(" />");
                result = sb.ToString();
            }
            return result;
        }

        #endregion

        #region Properties
        /// <summary>
        /// Stores Values from Data in a hastable for later reference
        /// </summary>
        public Hashtable DataValues
        {
            get
            {
                if (_dataValues == null)
                {
                    _dataValues = umbraco.helper.ReturnAttributes(string.Format("{0}", Data.Value));
                }
                return _dataValues;
            }
        }

        /// <summary>
        /// Holds a reference to the dropdownlist
        /// </summary>
        public DropDownList MacroSelectDropdown
        {
            get { return _macroSelectDropdown; }
            set { _macroSelectDropdown = value; }
        }

        /// <summary>
        /// Holds a reference to the selected Macro
        /// </summary>
        private string SelectedMacroAlias
        {
            get { return string.Format("{0}", ViewState["SelectedMacroAlias"]); }
            set { ViewState["SelectedMacroAlias"] = value; }
        }

        /// <summary>
        /// Holds a reference to the selected properties of the Macro
        /// </summary>
        private List<PersistableMacroProperties> SelectedProperties
        {
            get
            {
                if (ViewState["controls"] == null)
                {
                    return new List<PersistableMacroProperties>();
                }
                else
                {
                    return (List<PersistableMacroProperties>)ViewState["controls"];
                }
            }
            set
            {
                ViewState["controls"] = value;
            }
        }

        /// <summary>
        /// Holds a list of all Macros that are allowed to select
        /// </summary>
        public List<string> AllowedMacros
        {
            get { return _allowedMacros; }
            set { _allowedMacros = value; }
        }

        /// <summary>
        /// Holds a reference to the table where all controls are placed on
        /// </summary>
        public Table FormTable
        {
            get { return _formTable; }
            set { _formTable = value; }
        }

        #endregion

        #region IDataEditor Members

        /// <summary>
        /// The selected Editor
        /// </summary>
        public Control Editor
        {
            get { return this; ; }
        }

        /// <summary>
        /// Save button clicked
        /// </summary>
        public void Save()
        {
            EnsureChildControls();
            Data.Value = CreateUmbracoMacroTag();
        }

        /// <summary>
        /// Show the label
        /// </summary>
        public bool ShowLabel
        {
            get { return true; }
        }

        /// <summary>
        /// Tread control as a rich text editor
        /// </summary>
        public bool TreatAsRichTextEditor
        {
            get { return false; }
        }

        /// <summary>
        /// Holds a reference to the Data object
        /// </summary>
        public IData Data
        {
            get { return _data; }
            set { _data = value; }
        }
        #endregion
    }
}
